// Copyright (c) 2008-2010, Arne Claus
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
// following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this list of conditions and the following 
//   disclaimer.
// - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
//   disclaimer in the documentation and/or other materials provided with the distribution.
// - Neither the name Arne Claus nor the names of any contributors may be used to endorse or promote products
//   derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef __INCLUDED_CBL_TUPLE_H__
#define __INCLUDED_CBL_TUPLE_H__

#include "CBL_Defines.h"
#include "CBL_Debug.h"
#include "CBL_Math.h"
#include "CBL_Meta.h"
#include "CBL_Matrix.h"

#include <cstdarg>
#include <cstdlib>
#include <cstring>
#include <iostream>

// *************************************************************************************************
//! \class	CTuple
//! \brief	Generic class for multi-element mathematical constructs
// *************************************************************************************************

CB_SUBNAMESPACE_START(Math)

template <typename TType, uint32 TSize>
class CTuple
{	
public: 
	
	//! \note	All members will be initialized with 0.
	CTuple();
    
    //! \note	No members will be initialized.
    CTuple(EInitType) {}
	
	//! \note	This function expects to be called with an array of exactly TSize entries.
	//!			If this is not the case, there are two possibilities:
	//!			a) More arguments are provided -> spare entries will be ignored
	//!			b) Less arguments are provided -> undefined behavior for the remaining entries
	CTuple(const TType* _pData);
	
	//! \note	Sets X to _Value
	CTuple(TType _Value);
	
	//! \note	This function will only use the intersecting members.
	//!			All others will be initialized with 0.
	template <typename TType2, uint32 TSize2>
	CTuple(const CTuple<TType2, TSize2>& _rOther);	

	// ---------------------------------------------------------------------------------------------
	
public: 
	
	//! \note	This function will only override intersecting members.
	template<uint32 TSize2>
	CB_FORCEINLINE void CB_INLINE_ATTR operator = (const CTuple<TType, TSize2>& _rOther);
	
	//! \note	This function will only override intersecting members.
	//!			It will fail if a static_cast conversion is not possible.
	template<typename TType2, uint32 TSize2>
	CB_FORCEINLINE void CB_INLINE_ATTR operator = (const CTuple<TType2, TSize2>& _rOther);
	
	//! \note	This function expects to be called with an array of exactly TSize entries.
	//!			If this is not the case, there are two possibilities:
	//!			a) More arguments are provided -> spare entries will be ignored
	//!			b) Less arguments are provided -> undefined behavior for the remaining entries
	CB_FORCEINLINE void CB_INLINE_ATTR operator = (const TType* _pData);
	
	// ---------------------------------------------------------------------------------------------
	
public: 
	
	CB_FORCEINLINE TType& CB_INLINE_ATTR operator [] (uint32 _Index);
	CB_FORCEINLINE const TType& CB_INLINE_ATTR operator [] (uint32 _Index) const;	
	CB_FORCEINLINE TType* CB_INLINE_ATTR Array();
	CB_FORCEINLINE const TType* CB_INLINE_ATTR Array() const;
	
	// ---------------------------------------------------------------------------------------------
	
public:
	
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple& CB_INLINE_ATTR operator *= (const CTuple<TType2, TSize2>& _rRhs);
	
	CB_FORCEINLINE CTuple& CB_INLINE_ATTR operator *= (const TType& _rRhs);
	
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple& CB_INLINE_ATTR operator /= (const CTuple<TType2, TSize2>& _rRhs);
	
	CB_FORCEINLINE CTuple& CB_INLINE_ATTR operator /= (const TType& _rRhs);
	
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple& CB_INLINE_ATTR operator += (const CTuple<TType2, TSize2>& _rRhs);
	
	CB_FORCEINLINE CTuple& CB_INLINE_ATTR operator += (const TType& _rRhs);
	
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple& CB_INLINE_ATTR operator -= (const CTuple<TType2, TSize2>& _rRhs);
	
	CB_FORCEINLINE CTuple& CB_INLINE_ATTR operator -= (const TType& _rRhs);
	
	// ---------------------------------------------------------------------------------------------
	
public: 
	
	//! \brief	Compares two vectors, using the minimum row count. Returns a vector of the size of
	//!			the left-hand-side parameter.
	//!			All elements in rows bigger than the minimum row count are set to false.
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple<bool, TSize> CB_INLINE_ATTR operator == (const CTuple<TType2, TSize2>& _rRhs) const;
	
	//! \brief	Compares two vectors, using the minimum row count. Returns a vector of the size of
	//!			the left-hand-side parameter.
	//!			All elements in rows bigger than the minimum row count are set to true.
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple<bool, TSize> CB_INLINE_ATTR operator != (const CTuple<TType2, TSize2>& _rRhs) const;
	
	//! \brief	Compares two vectors, using the minimum row count. Returns a vector of the size of
	//!			the left-hand-side parameter.
	//!			All elements in rows bigger than the minimum row count are set to false.
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple<bool, TSize> CB_INLINE_ATTR operator < (const CTuple<TType2, TSize2>& _rRhs) const;
	
	//! \brief	Compares two vectors, using the minimum row count. Returns a vector of the size of
	//!			the left-hand-side parameter.
	//!			All elements in rows bigger than the minimum row count are set to false.
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple<bool, TSize> CB_INLINE_ATTR operator <= (const CTuple<TType2, TSize2>& _rRhs) const;
	
	//! \brief	Compares two vectors, using the minimum row count. Returns a vector of the size of
	//!			the left-hand-side parameter.
	//!			All elements in rows bigger than the minimum row count are set to true.
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple<bool, TSize> CB_INLINE_ATTR operator > (const CTuple<TType2, TSize2>& _rRhs) const;
	
	//! \brief	Compares two vectors, using the minimum row count. Returns a vector of the size of
	//!			the left-hand-side parameter.
	//!			All elements in rows bigger than the minimum row count are set to true.
	template <typename TType2, uint32 TSize2>
	CB_FORCEINLINE CTuple<bool, TSize> CB_INLINE_ATTR operator >= (const CTuple<TType2, TSize2>& _rRhs) const;
	
	//! \brief	Compares two vectors, using the minimum row count. Returns true if the difference between
	//!			all overlapping elements are inside epsilon range.
	CB_FORCEINLINE bool CB_INLINE_ATTR AlmostEq(const CTuple<TType, TSize>& _rRhs, float _Epsilon=0.0001f) const;
	
public: 
	
	CB_FORCEINLINE TType CB_INLINE_ATTR LengthSqr() const;
	CB_FORCEINLINE TType CB_INLINE_ATTR Length() const;
	CB_FORCEINLINE void CB_INLINE_ATTR Normalize();
		
public: 
	
	static const uint32		s_MemSize = sizeof(TType) * TSize;
	
protected: 
	
	TType					m_Values[TSize];
};

// -------------------------------------------------------------------------------------------------
//  Utility functions
// -------------------------------------------------------------------------------------------------

template <typename TType, uint32 TSize>
CB_FORCEINLINE CTuple<TType, TSize> CB_INLINE_ATTR Sqrt(CTuple<TType, TSize> _Value);

template <typename TType, uint32 TSize>
CB_FORCEINLINE CTuple<TType, TSize> CB_INLINE_ATTR Floor(CTuple<TType, TSize> _Value);

template <typename TType, typename TType2, uint32 TSize>
CB_FORCEINLINE TType CB_INLINE_ATTR Dot(const CTuple<TType, TSize>& _rLhs, const CTuple<TType2, TSize>& _rRhs);

template <typename TType, typename TType2, uint32 TSize>
CB_FORCEINLINE CTuple<TType, TSize> CB_INLINE_ATTR Clamp(CTuple<TType, TSize> _Value,  const CTuple<TType, TSize>& _rMin, const CTuple<TType2, TSize>& _rMax);

template <typename TType, uint32 TSize>
CB_FORCEINLINE CTuple<TType, TSize> CB_INLINE_ATTR Normalize(CTuple<TType, TSize> _Value);

// -------------------------------------------------------------------------------------------------

//! \brief	Calculates a 3-Component cross product and sets the 4th value to the 4th value of the
//!			left-hand-side parameter.
template <typename TType, typename TType2>
CB_FORCEINLINE CTuple<TType, 4> CB_INLINE_ATTR Cross(const CTuple<TType, 4>& _rLhs, const CTuple<TType2, 4>& _rRhs);

template <typename TType, typename TType2>
CB_FORCEINLINE CTuple<TType, 3> CB_INLINE_ATTR Cross(const CTuple<TType, 3>& _rLhs, const CTuple<TType2, 3>& _rRhs);

// -------------------------------------------------------------------------------------------------
//  Operators
// -------------------------------------------------------------------------------------------------

template <typename TType, typename TType2, uint32 TSize>
CB_FORCEINLINE CTuple<TType, TSize> CB_INLINE_ATTR operator + (const CTuple<TType, TSize> _rLhs, const CTuple<TType2, TSize>& _rRhs);

template <typename TType, typename TType2, uint32 TSize>
CB_FORCEINLINE CTuple<TType, TSize> CB_INLINE_ATTR operator - (const CTuple<TType, TSize> _rLhs, const CTuple<TType2, TSize>& _rRhs);

template <typename TType, typename TType2, uint32 TSize>
CB_FORCEINLINE CTuple<TType, TSize> CB_INLINE_ATTR operator * (const CTuple<TType, TSize> _rLhs, const CTuple<TType2, TSize>& _rRhs);

template <typename TType, typename TType2, uint32 TSize>
CB_FORCEINLINE CTuple<TType, TSize> CB_INLINE_ATTR operator / (const CTuple<TType, TSize> _rLhs, const CTuple<TType2, TSize>& _rRhs);

template <typename TType, uint32 TSize>
CB_FORCEINLINE std::ostream& CB_INLINE_ATTR operator << (std::ostream& _rLhs, CTuple<TType, TSize>& _rRhs);

// -------------------------------------------------------------------------------------------------
//	Matrix operators
// -------------------------------------------------------------------------------------------------

#ifdef CBL_MATRIX_COL_MAJOR
template <typename TVecType, typename TMtxType, uint32 TRowSize, uint32 TColSize>
CB_FORCEINLINE CTuple<TVecType, TRowSize> CB_INLINE_ATTR operator * (const CTuple<TVecType, TRowSize>& _rLhs, const CMatrix<TMtxType, TColSize, TRowSize>& _rRhs);
#else
template <typename TVecType, typename TMtxType, uint32 TRowSize, uint32 TColSize>
CB_FORCEINLINE CTuple<TVecType, TColSize> CB_INLINE_ATTR operator * (const CTuple<TVecType, TColSize>& _rLhs, const CMatrix<TMtxType, TRowSize, TColSize>& _rRhs);
#endif

// -------------------------------------------------------------------------------------------------
//	Compare helper
// -------------------------------------------------------------------------------------------------

template <typename TType, uint32 TSize>
CB_FORCEINLINE bool CB_INLINE_ATTR All(const CTuple<TType, TSize>& _rVector, uint32 _Size=TSize);

template <typename TType, uint32 TSize>
CB_FORCEINLINE bool CB_INLINE_ATTR Any(const CTuple<TType, TSize>& _rVector, uint32 _Size=TSize);

template <typename TType, uint32 TSize>
CB_FORCEINLINE bool CB_INLINE_ATTR None(const CTuple<TType, TSize>& _rVector, uint32 _Size=TSize);

// -------------------------------------------------------------------------------------------------
//	Predefined types
// -------------------------------------------------------------------------------------------------

#include "CBL_TupleTypes.hpp"

typedef CTuple4<float>	Float4;
typedef CTuple3<float>	Float3;
typedef CTuple2<float>	Float2;

typedef CTuple4<int32>	Int4;
typedef CTuple3<int32>	Int3;
typedef CTuple2<int32>	Int2;

typedef CTuple4<uint32>	UInt4;
typedef CTuple3<uint32>	UInt3;
typedef CTuple2<uint32>	UInt2;

typedef CTuple4<bool>	Bool4;
typedef CTuple3<bool>	Bool3;
typedef CTuple2<bool>	Bool2;

// -------------------------------------------------------------------------------------------------
//  Implementation
// -------------------------------------------------------------------------------------------------

#include "CBL_Tuple.hpp"

CB_SUBNAMESPACE_END

#endif